﻿using FCSChart.Axis;
using FCSChart.Series;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace FCSChart
{
    [TemplatePart(Name = "Part_Panel", Type = typeof(Panel))]
    public class Chart : Control
    {
        /// <summary>
        /// Part_Panel的背景色
        /// </summary>
        public Brush PanelBackground
        {
            get { return (Brush)GetValue(PanelBackgroundProperty); }
            set { SetValue(PanelBackgroundProperty, value); }
        }
        public static readonly DependencyProperty PanelBackgroundProperty = DependencyProperty.Register("PanelBackground", typeof(Brush), typeof(Chart), new PropertyMetadata(Brushes.White));

        static Chart()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Chart), new FrameworkPropertyMetadata(typeof(Chart)));
        }

        public Chart()
        {
            this.Loaded += (sender, e) =>
            {
                DrawingSeries();
            };
        }

        #region property
        /// <summary>
        /// X轴数据源
        /// </summary>
        public IList XSource
        {
            get { return (IList)GetValue(XSourceProperty); }
            set { SetValue(XSourceProperty, value); }
        }
        public static readonly DependencyProperty XSourceProperty = DependencyProperty.Register("XSource", typeof(IList), typeof(Chart), new PropertyMetadata((d, e) =>
        {
            if (d is Chart temp && temp.IsLoaded) temp.DrawingSeries();
        }));

        /// <summary>
        /// Y轴数据源
        /// </summary>
        public IList YSource
        {
            get { return (IList)GetValue(YSourceProperty); }
            set { SetValue(YSourceProperty, value); }
        }
        public static readonly DependencyProperty YSourceProperty = DependencyProperty.Register("YSource", typeof(IList), typeof(Chart), new PropertyMetadata((d, e) =>
        {
            if (d is Chart temp && temp.IsLoaded && (temp.Series == null || !"Histogram".Equals(temp.Series.SeriesName))) temp.DrawingSeries();
        }));

        /// <summary>
        /// 需要显示的索引值,为null时显示数据源的所有
        /// </summary>
        public IList<int> Indexs
        {
            get { return (IList<int>)GetValue(IndexsProperty); }
            set { SetValue(IndexsProperty, value); }
        }
        public static readonly DependencyProperty IndexsProperty = DependencyProperty.Register("Indexs", typeof(IList<int>), typeof(Chart), new PropertyMetadata((d, e) =>
        {
            if (d is Chart temp && temp.IsLoaded) temp.DrawingSeries();
        }));

        /// <summary>
        /// xSource的值转换，fcs文件中有通道值转刻度值
        /// </summary>
        public Func<object, double> XValueConverter
        {
            get { return (Func<object, double>)GetValue(XValueConverterProperty); }
            set { SetValue(XValueConverterProperty, value); }
        }
        public static readonly DependencyProperty XValueConverterProperty = DependencyProperty.Register("XValueConverter", typeof(Func<object, double>), typeof(Chart), new PropertyMetadata((d, e) => { if (d is Chart temp && temp.IsLoaded) temp.DrawingSeries(); }));
        /// <summary>
        /// ySource的值转换，fcs文件中有通道值转刻度值
        /// </summary>
        public Func<object, double> YValueConverter
        {
            get { return (Func<object, double>)GetValue(YValueConverterProperty); }
            set { SetValue(YValueConverterProperty, value); }
        }
        public static readonly DependencyProperty YValueConverterProperty = DependencyProperty.Register("YValueConverter", typeof(Func<object, double>), typeof(Chart), new PropertyMetadata((d, e) => { if (d is Chart temp && temp.IsLoaded) temp.DrawingSeries(); }));

        /// <summary>
        /// 显示数据的图形
        /// </summary>
        public ISeries Series
        {
            get { return (ISeries)GetValue(SeriesProperty); }
            set { SetValue(SeriesProperty, value); }
        }
        public static readonly DependencyProperty SeriesProperty = DependencyProperty.Register("Series", typeof(ISeries), typeof(Chart), new PropertyMetadata((sender, e) => { if (sender is Chart chart && e.NewValue is ISeries series) series.OwnerChart = chart; }));

        #region 轴类型
        /// <summary>
        /// x轴
        /// </summary>
        public IAxis XAxis
        {
            get { return (IAxis)GetValue(XAxisProperty); }
            set { SetValue(XAxisProperty, value); }
        }
        public static readonly DependencyProperty XAxisProperty = DependencyProperty.Register("XAxis", typeof(IAxis), typeof(Chart), new PropertyMetadata(XAxis_Changed));
        private static void XAxis_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender is Chart chart)
            {
                if (e.NewValue is IAxis axis)
                {
                    axis.XYType = AxisType.X;
                    axis.OwnerChart = chart;
                }
            }
        }

        /// <summary>
        /// y轴
        /// </summary>
        public IAxis YAxis
        {
            get { return (IAxis)GetValue(YAxisProperty); }
            set { SetValue(YAxisProperty, value); }
        }
        public static readonly DependencyProperty YAxisProperty = DependencyProperty.Register("YAxis", typeof(IAxis), typeof(Chart), new PropertyMetadata(YAxis_Changed));
        private static void YAxis_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (sender is Chart chart)
            {
                if (e.NewValue is IAxis axis)
                {
                    axis.XYType = AxisType.Y;
                    axis.OwnerChart = chart;
                }
            }
        }

        /// <summary>
        /// 属性改变需要重新绘制
        /// </summary>
        internal virtual void ChangedNeedRedrawing()
        {
            DrawingSeries();
        }
        #endregion

        #region 变形
        /// <summary>
        /// 缩放方式
        /// </summary>
        public AxisChangeType ZoomType
        {
            get { return (AxisChangeType)GetValue(ZoomTypeProperty); }
            set { SetValue(ZoomTypeProperty, value); }
        }
        public static readonly DependencyProperty ZoomTypeProperty = DependencyProperty.Register("ZoomType", typeof(AxisChangeType), typeof(Chart), new PropertyMetadata(AxisChangeType.None));

        /// <summary>
        /// 移动方式
        /// </summary>
        public AxisChangeType MoveType
        {
            get { return (AxisChangeType)GetValue(MoveTypeProperty); }
            set { SetValue(MoveTypeProperty, value); }
        }
        public static readonly DependencyProperty MoveTypeProperty = DependencyProperty.Register("MoveType", typeof(AxisChangeType), typeof(Chart), new PropertyMetadata(AxisChangeType.None));
        #endregion

        #endregion

        #region 重载
        /// <summary>
        /// 加载模板
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.MouseDown += (sender, e) => { this.Focus(); };
            var temp = GetTemplateChild("Part_Panel");
            if (temp != null)
            {
                ViewPanel = temp as Panel;
                ViewPanel.MouseLeftButtonDown += Panel_MouseLeftButtonDown;
                ViewPanel.MouseLeftButtonUp += Panel_MouseLeftButtonUp;
                ViewPanel.MouseMove += Panel_MouseMove;
                ViewPanel.MouseWheel += Panel_MouseWheel;
            }
        }

        /// <summary>
        /// 尺寸变化时重新绘制图形
        /// </summary>
        /// <param name="sizeInfo"></param>
        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);
            XAxis?.Drawing();
            YAxis?.Drawing();
        }
        #endregion

        #region 鼠标控制事件
        internal Panel ViewPanel { get; set; }
        protected Point moveStartPoint;
        bool isMoved = false;
        /// <summary>
        /// 鼠标左键按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Panel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            moveStartPoint = e.GetPosition(ViewPanel);
        }
        /// <summary>
        /// 鼠标抬起
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Panel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (isMoved)
            {
                DrawingSeries(false);
                isMoved = false;
            }
        }
        /// <summary>
        /// 鼠标移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Panel_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                if (moveStartPoint != default)
                {
                    var point = e.GetPosition(ViewPanel);
                    var x = point.X - moveStartPoint.X;
                    var y = point.Y - moveStartPoint.Y;
                    moveStartPoint = point;
                    Move(x, y, MoveType);
                    isMoved = true;
                }
            }
            else moveStartPoint = default;
        }
        /// <summary>
        /// 鼠标滚动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Panel_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (ZoomType == AxisChangeType.None) return;
            var point = e.GetPosition(ViewPanel);
            var percent = e.Delta > 0 ? 1.1d : 0.9d;
            Zoom(point, percent, ZoomType);
            e.Handled = true;
        }
        #endregion

        #region function
        /// <summary>
        /// 移动图形
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="moveType"></param>
        internal virtual void Move(double x, double y, AxisChangeType moveType)
        {
            if (moveType == AxisChangeType.None) return;
            switch (moveType)
            {
                case AxisChangeType.None:
                    break;
                case AxisChangeType.X:
                    XAxis?.Move(x, 0);
                    y = 0;
                    break;
                case AxisChangeType.Y:
                    YAxis?.Move(0, y);
                    x = 0;
                    break;
                case AxisChangeType.XY:
                    XAxis?.Move(x, y);
                    YAxis?.Move(x, y);
                    break;
                default:
                    break;
            }
            Series?.Move(x, y);
        }
        /// <summary>
        /// 缩放图形
        /// </summary>
        /// <param name="point"></param>
        /// <param name="percent"></param>
        /// <param name="zoomType"></param>
        internal virtual void Zoom(Point point, double percent, AxisChangeType zoomType)
        {
            if (zoomType == AxisChangeType.None) return;
            switch (zoomType)
            {
                case AxisChangeType.None:
                    break;
                case AxisChangeType.X:
                    XAxis?.Zoom(percent, point);
                    break;
                case AxisChangeType.Y:
                    YAxis?.Zoom(percent, point);
                    break;
                case AxisChangeType.XY:
                    XAxis?.Zoom(percent, point);
                    YAxis?.Zoom(percent, point);
                    break;
                default:
                    break;
            }
            DrawingSeries(false);
        }
        /// <summary>
        /// 重新绘制图形
        /// </summary>
        protected virtual void DrawingSeries(bool NeedRefreshAreaSource = true)
        {
            if (!IsLoaded || Series == null) return;
            Series.Drawing();
        }

        #endregion
    }
}
